﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace WFL.Data
{
    public class PropertyDefinition
    {
        public static PropertyDefinition Create(PropertyInfo propertyInfo, string provider)
        {
            PropertyDefinition item = new PropertyDefinition();
            item.PropertyInfo = propertyInfo;
            item.Persist.Behaviors = PersistBehaviors.Select | PersistBehaviors.Insert | PersistBehaviors.Update;
            object[] attributes = propertyInfo.GetCustomAttributes(typeof(DefinitionAttribute), true);
            if (attributes != null && attributes.Length > 0)
            {
                FieldAttribute lastFieldAttribute = null;
                foreach (object attribute in attributes)
                {
                    if (attribute is PersistAttribute)
                    {
                        item.Persist.Behaviors = ((PersistAttribute)attribute).Behaviors;
                        if (item.Persist.Behaviors == PersistBehaviors.None)
                        {
                            return null;
                        }
                    }
                    else if (attribute is FieldAttribute)
                    {
                        FieldAttribute fieldAttribute = (FieldAttribute)attribute;
                        if (string.IsNullOrEmpty(fieldAttribute.Provider))
                        {
                            if (lastFieldAttribute == null
                                || string.IsNullOrEmpty(lastFieldAttribute.Provider))
                            {
                                lastFieldAttribute = fieldAttribute;
                                item.Field.Name = fieldAttribute.Name;
                                item.Field.DbType = fieldAttribute.DbType;
                            }
                        }
                        else if (fieldAttribute.Provider.Equals(provider, StringComparison.InvariantCulture))
                        {
                            lastFieldAttribute = fieldAttribute;
                            item.Field.Name = fieldAttribute.Name;
                            item.Field.DbType = fieldAttribute.DbType;
                        }
                    }
                    else if (attribute is PrimaryKeyAttribute)
                    {
                        item.PrimaryKey = new PrimaryKeyInfo();
                        item.PrimaryKey.Automatic = ((PrimaryKeyAttribute)attribute).Automatic;
                    }
                    else if (attribute is ForeignKeyAttribute)
                    {
                        ForeignKeyAttribute tempAttribute = (ForeignKeyAttribute)attribute;
                        item.ForeignKey = new ForeignKeyInfo();
                        item.ForeignKey.ReferenceType = tempAttribute.ReferenceType;
                        item.ForeignKey.ReferencePropertyName = tempAttribute.ReferencePropertyName;
                        if (string.IsNullOrEmpty(item.ForeignKey.ReferencePropertyName))
                        {
                            //没有指定外键关联到的主键属性名称
                            //从当前属性名称开头部分中截去外键引用的主键类型名称来获得主键属性名称
                            if (!item.PropertyInfo.Name.StartsWith(item.ForeignKey.ReferenceType.Name))
                            {
                                throw new Exception(string.Format("无法确定类型\"{0}\"的外键\"{1}\"引用的主键属性名称"
                                    , item.PropertyInfo.DeclaringType.FullName
                                    , item.PropertyInfo.Name));
                            }
                            item.ForeignKey.ReferencePropertyName = item.PropertyInfo.Name.Substring(item.ForeignKey.ReferenceType.Name.Length);
                        }
                    }
                    else
                    {
                        throw new NotSupportedException(string.Format("未支持的特性\"{0}\"", attribute.GetType().FullName));
                    }
                }
            }
            if (string.IsNullOrEmpty(item.Field.Name))
            {
                item.Field.Name = propertyInfo.Name;
            }
            return item;
        }

        public PropertyInfo PropertyInfo 
        { 
            get; 
            set; 
        }

        public PrimaryKeyInfo PrimaryKey
        {
            get;
            set;
        }

        public ForeignKeyInfo ForeignKey
        {
            get;
            set;
        }

        public PersistInfo Persist
        {
            get;
            set;
        }

        public FieldInfo Field
        {
            get;
            set;
        }

        private PropertyDefinition()
        {
            Persist = new PersistInfo();
            Field = new FieldInfo();
        }
    }
}
